package classfile

// 代表一个常量池的数组。每一个类都有一个常量池，用来存放这个类的常量。
// 这个常量池位于class文件中，在解析后组成这个结构体用来表示class文件中的常量池
// 在java应用运行时，这个常量池被加载到方法区（元空间），成为运行时常量池。程序运行时每个类都有一个运行时常量池
type ConstantPool []ConstantInfo

func readConstantPool(reader *ClassReader) ConstantPool {
	// 两个字节指定常量池大小，常量池实际元素个数比它要小，因为CONSTANT_Double_info和CONSTANT_LONG_INFO都占两个索引位置
	// 用两个字节指定大小，意味着一个类或接口中常量池项个数不能超过65535个。因为两个字节能表示的最大的数就是65535
	cpCount := int(reader.ReadUint16())
	cp := make([]ConstantInfo, cpCount)

	// 常量池索引从1开始
	for i := 1; i < cpCount; i++ {
		// 正式读取常量池，常量池中每一项都是 tag（1字节，指定下一个常量的类型）+ 实际常量结构
		cp[i] = readConstantInfo(reader, cp)
		switch cp[i].(type) {
		case *ConstantLongInfo, *ConstantDoubleInfo:
			i++ // 占两个位置
		}
	}
	// 读取完成，返回常量池
	return cp
}

func (self ConstantPool) getConstantInfo(index uint16) ConstantInfo {
	if cpInfo := self[index]; cpInfo != nil {
		return cpInfo
	}
	panic("Invalid constat pool index")
}

func (self ConstantPool) getNameAndType(index uint16) (string, string) {
	ntInfo := self.getConstantInfo(index).(*ConstantNameAndTypeInfo)
	name := self.getUtf8(ntInfo.nameIndex)
	_type := self.getUtf8(ntInfo.descriptorIndex)
	return name, _type
}
func (self ConstantPool) getClassName(index uint16) string {
	classInfo := self.getConstantInfo(index).(*ConstantClassInfo)
	return self.getUtf8(classInfo.nameIndex)
}
func (self ConstantPool) getUtf8(index uint16) string {
	info := self.getConstantInfo(index)
	utf8Info := info.(*ConstantUtf8Info)
	return utf8Info.str
}
